package org.jeecg.modules.xxgx.cxtj.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.modules.common.util.LoginUserUtil;
import org.jeecg.modules.common.util.MathUtil;
import org.jeecg.modules.innerApi.common.requestDto.CommonParam;
import org.jeecg.modules.xxgx.common.enums.FpztEnum;
import org.jeecg.modules.xxgx.common.enums.KplxEnum;
import org.jeecg.modules.xxgx.common.util.ExcelUtils;
import org.jeecg.modules.xxgx.common.util.PoiUtils;
import org.jeecg.modules.xxgx.cxtj.param.XxFptjKehuPageParam;
import org.jeecg.modules.xxgx.cxtj.param.XxFptjKehuParam;
import org.jeecg.modules.xxgx.cxtj.param.XxFptjSeParam;
import org.jeecg.modules.xxgx.cxtj.param.XxFptjSlParam;
import org.jeecg.modules.xxgx.cxtj.service.ICsXxFptjService;
import org.jeecg.modules.xxgx.cxtj.vo.XxFptjKehuDTO;
import org.jeecg.modules.xxgx.cxtj.vo.XxFptjSeDTO;
import org.jeecg.modules.xxgx.cxtj.vo.XxFptjSlDTO;
import org.jeecg.modules.xxgx.cxtj.vo.XxFptjSlMxDTO;
import org.jeecg.modules.xxgx.kpzdgl.service.ICsXxKpzdService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

@Api(tags = "发票统计")
@RestController
@RequestMapping("/xxgx/fptj")
@Slf4j
public class CsXxFptjController {
    @Autowired
    private ICsXxFptjService fptjService;
    @Autowired
    private ICsXxKpzdService kpzdService;

    @AutoLog(value = "发票统计-按税率")
    @ApiOperation(value = "发票统计-按税率", notes = "发票统计-按税率")
    @PostMapping(value = "/fptjSl")
    public Result<JSONObject> fptjSl(@RequestBody XxFptjSlParam param) {
        JSONObject resultJson = getFptjSlData(param);
        return Result.OK(resultJson);
    }

    /**
     * 按税率统计数据结果
     *
     * @param param
     * @return
     */
    private JSONObject getFptjSlData(XxFptjSlParam param) {
        String nsrsbh = LoginUserUtil.getQyxxByLoginUser().getNsrsbh();
        if (StringUtils.isNotEmpty(param.getKpzddm())) {
            CommonParam commonParam = kpzdService.getCommonParamByKpzd(param.getKpzddm());
            nsrsbh = commonParam.getQyxx().getNsrsbh();
        }

        if (StringUtils.isNotBlank(param.getSysOrgCode())) {
            String[] orgcodes = param.getSysOrgCode().split(",");
            param.setSysOrgCodeArr(new ArrayList<>(Arrays.asList(orgcodes)));
        } else {
            //选部门  有可能选到其他公司的部门  所以如果不传部门  才加上税号的查询条件
            param.setNsrsbh(nsrsbh);
        }


        JSONObject resultJson = new JSONObject();
        XxFptjSlDTO xxFptjSlDTO = fptjService.getXxFpxxtjHj(param);
        resultJson.put("statData", xxFptjSlDTO);

        List<XxFptjSlMxDTO> list = fptjService.getXxFpxxtjMx(param);
        Map<String, Object> tmpMap = converData(list);

        //第二个表格头对象定义
        resultJson.put("statMxTitle", tmpMap.get("titleField"));

        //第二个表格明细数据
        resultJson.put("statMxRow", tmpMap.get("row"));

        return resultJson;
    }

    /**
     * 转换数据格式
     *
     * @param list
     * @return
     */
    private Map<String, Object> converData(List<XxFptjSlMxDTO> list) {
        Map<String, Object> resultMap = new HashMap<>();

        //表头信息list
        ArrayList<String> colsList = new ArrayList<>();
        //表格表头Map对应
        Map<String, Object> titleFieldMap = new LinkedHashMap<String, Object>();

        Map tmpFieldMap = new HashMap();
        tmpFieldMap.put("title", "项目名称");
        tmpFieldMap.put("dataIndex", "ItemName");
        tmpFieldMap.put("align", "center");
        titleFieldMap.put("ItemName", tmpFieldMap);

        tmpFieldMap = new HashMap();
        tmpFieldMap.put("dataIndex", "hj");
        tmpFieldMap.put("title", "合计");
        tmpFieldMap.put("align", "center");
        titleFieldMap.put("hj", tmpFieldMap);

        //统计表行数据map
        Map<String, Object> dataMap = getTotalDataTemplate();

        for (XxFptjSlMxDTO xxFptjSlMxDTO : list) {
            String fpztmc = "";
            if (FpztEnum.zc.getValue().equals(xxFptjSlMxDTO.getFpzt())) {
                fpztmc = "00";
            } else if (FpztEnum.hc.getValue().equals(xxFptjSlMxDTO.getFpzt())) {
                fpztmc = "01";
            } else if (FpztEnum.zf.getValue().equals(xxFptjSlMxDTO.getFpzt()) && KplxEnum.ZSFP.getValue().equals(xxFptjSlMxDTO.getKplx())) {
                fpztmc = "03";
            } else if (FpztEnum.zf.getValue().equals(xxFptjSlMxDTO.getFpzt()) && KplxEnum.FSFP.getValue().equals(xxFptjSlMxDTO.getKplx())) {
                fpztmc = "04";
            }

            if (xxFptjSlMxDTO.getTax() == null) {
                continue;
            }
            int tax = xxFptjSlMxDTO.getTax().multiply(new BigDecimal("100")).intValue();

            //定义列字段名
            String fieldName = getTaxFieldName(tax);
            //获取对应发票状态的金额对象
            Map tmpRowAmountMap = (Map) dataMap.get(fpztmc + "_0");
            //获取对应发票状态的税额对象
            Map tmpRowTaxAmountMap = (Map) dataMap.get(fpztmc + "_1");
            if (tmpRowAmountMap != null) {
                tmpRowAmountMap.put(fieldName, xxFptjSlMxDTO.getBhsje());
            }
            if (tmpRowTaxAmountMap != null) {
                tmpRowTaxAmountMap.put(fieldName, xxFptjSlMxDTO.getTaxje());
            }

            //动态组装第二个表络的表头税率对象
            if (!titleFieldMap.containsKey(fieldName)) {
                tmpFieldMap = new HashMap();
                tmpFieldMap.put("dataIndex", fieldName);
                tmpFieldMap.put("title", Integer.valueOf(tax) + "%");
                tmpFieldMap.put("align", "center");
                titleFieldMap.put(fieldName, tmpFieldMap);
                colsList.add(Integer.valueOf(tax) + "%");
            }
        }

        //以发票状态行为金额的对象转换成行数据
        List<Map> rowList = new ArrayList<>();
        for (String keyName : dataMap.keySet()) {
            Map<String, Object> rowMap = (Map) dataMap.get(keyName);

            BigDecimal totalAmount = new BigDecimal("0");

            //合计以f_tax_开头的字段税率总金额
            for (String itemName : rowMap.keySet()) {
                if (itemName.startsWith("f_tax_")) {
                    totalAmount = MathUtil.add(totalAmount, (BigDecimal) rowMap.get(itemName));
                }
            }
            rowMap.put("hj", totalAmount);

            //判断 销项正数金额 销项负数金额 正数税额 负数税额
            if (keyName.equals("00_0") || keyName.equals("01_0")) {
                BigDecimal totalAmount1 = new BigDecimal("0");
                Map<String, Object> rowMap1 = (Map) dataMap.get("05_0");
                for (String itemName : rowMap.keySet()) {
                    if (itemName.startsWith("f_tax_")) {
                        BigDecimal r1 = (BigDecimal) rowMap.get(itemName);
                        BigDecimal r2 = (BigDecimal) rowMap1.get(itemName);

                        if (rowMap1.get(itemName) != null) {
                            rowMap1.put(itemName, MathUtil.add(r1, r2));
                        } else {
                            rowMap1.put(itemName, r1);
                        }
                        totalAmount1 = MathUtil.add(totalAmount1, r1);
                    }
                }
                rowMap1.put("hj", totalAmount1);
            }
            if (keyName.equals("00_1") || keyName.equals("01_1")) {
                BigDecimal totalAmount1 = new BigDecimal("0");
                Map<String, Object> rowMap1 = (Map) dataMap.get("05_1");
                for (String itemName : rowMap.keySet()) {
                    if (itemName.startsWith("f_tax_")) {
                        BigDecimal r1 = (BigDecimal) rowMap.get(itemName);
                        BigDecimal r2 = (BigDecimal) rowMap1.get(itemName);

                        if (rowMap1.get(itemName) != null) {
                            rowMap1.put(itemName, MathUtil.add(r1, r2));
                        } else
                            rowMap1.put(itemName, r1);
                        totalAmount1 = MathUtil.add(totalAmount1, r1);
                    }
                }
                rowMap1.put("hj", totalAmount1);
            }
            rowList.add(rowMap);
        }

        //第二个表格列标题对象定义
        List<Map> titleList = new ArrayList<>();
        for (String keyName : titleFieldMap.keySet()) {
            titleList.add((Map) titleFieldMap.get(keyName));
        }
        //第二个表格列标题对象
        resultMap.put("titleField", titleList);
        //第二个表格数据对象
        resultMap.put("row", rowList);
        return resultMap;
    }

    /**
     * 数据行
     *
     * @return
     */
    private Map getTotalDataTemplate() {
        Map<String, Object> itemmap = new LinkedHashMap<String, Object>();
        Map rowMap = new HashMap();
        rowMap.put("ItemName", "销项正数金额");
        //格式:发票状态_金额或税额
        itemmap.put("00_0", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "销项正废金额");
        itemmap.put("03_0", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "销项负数金额");
        itemmap.put("01_0", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "销项负废金额");
        itemmap.put("04_0", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "实际销售金额");
        itemmap.put("05_0", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "销项正数税额");
        itemmap.put("00_1", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "销项正废税额");
        itemmap.put("03_1", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "销项负数税额");
        itemmap.put("01_1", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "销项负废税额");
        itemmap.put("04_1", rowMap);

        rowMap = new HashMap();
        rowMap.put("ItemName", "实际销项税额");
        itemmap.put("05_1", rowMap);
        return itemmap;
    }

    private String getTaxFieldName(int tax) {
        return "f_tax_" + Integer.valueOf(tax);
    }

    @ApiOperation(value = "发票统计-按税率-导出excel", notes = "发票统计-按税率-导出excel")
    @RequestMapping(value = "/fptjSlExportXls", method = RequestMethod.POST)
    public void fptjSlExportXls(HttpServletRequest request, HttpServletResponse response, @RequestBody XxFptjSlParam param) throws IOException {
        JSONObject resultJson = getFptjSlData(param);
        String title = "发票统计(按税率)";
        SXSSFWorkbook wb = new SXSSFWorkbook();
        try {
            Sheet sheet = wb.createSheet(title);

            int rowIndex = 0;//行号

            String[] titles = "正数发票份数,负数发票份数,正数废票份数,负数废票份数,空白废票份数,合计发票份数,实际销售金额,实际销项税额".split(",");
            String[] dataKeys = "fpfsZs,fpfsFs,fpfsZszf,fpfsFszf,fpfsKb,fpfsTotal,hjje,hjse".split(",");
            rowIndex = PoiUtils.writeTitlesToExcel(wb, sheet, titles, rowIndex);

            JSONObject statData = resultJson.getJSONObject("statData");
            Map<String, Object> map = statData.toJavaObject(Map.class);

            List<Map<String, Object>> dataList = new ArrayList<>();
            dataList.add(map);
            rowIndex = PoiUtils.writeRowsToExcel(wb, sheet, dataKeys, dataList, rowIndex);

            PoiUtils.autoSizeColumns(sheet, dataKeys.length);

            rowIndex++;//第一个表格后空一行

            //第二个表格
            JSONArray mxTitleArray = resultJson.getJSONArray("statMxTitle");
            JSONArray mxRow = resultJson.getJSONArray("statMxRow");

            Map mxTitleObject;
            List<String> title2List = new ArrayList();
            List<String> key2List = new ArrayList();
            for (int i = 0; i < mxTitleArray.size(); i++) {
                mxTitleObject = (Map) mxTitleArray.get(i);
                title2List.add(String.valueOf(mxTitleObject.get("title")));
                key2List.add(String.valueOf(mxTitleObject.get("dataIndex")));
            }
            titles = title2List.toArray(new String[title2List.size()]);
            dataKeys = key2List.toArray(new String[key2List.size()]);
            rowIndex = PoiUtils.writeTitlesToExcel(wb, sheet, titles, rowIndex);

            //数据行
            List<Map<String, Object>> rowList = JSONArray.parseObject(mxRow.toJSONString(), new TypeReference<List<Map<String, Object>>>() {
            });
            rowIndex = PoiUtils.writeRowsToExcel(wb, sheet, dataKeys, rowList, rowIndex);

            PoiUtils.autoSizeColumns(sheet, dataKeys.length);

            String fileName = "发票统计(按税率)";
            PoiUtils.downLoadExcel(fileName, response, wb);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            wb.close();
        }
    }

    @AutoLog(value = "发票统计-按客户")
    @ApiOperation(value = "发票统计-按客户", notes = "发票统计-按客户")
    @PostMapping(value = "/fptjKehu")
    public Result<IPage<XxFptjKehuDTO>> fptjKehu(@RequestBody XxFptjKehuPageParam param) {
        String nsrsbh = LoginUserUtil.getQyxxByLoginUser().getNsrsbh();
        if (StringUtils.isNotEmpty(param.getKpzddm())) {
            CommonParam commonParam = kpzdService.getCommonParamByKpzd(param.getKpzddm());
            nsrsbh = commonParam.getQyxx().getNsrsbh();
        }

        if (StringUtils.isNotBlank(param.getSysOrgCode())) {
            String[] orgcodes = param.getSysOrgCode().split(",");
            param.setSysOrgCodeArr(new ArrayList<>(Arrays.asList(orgcodes)));
        } else {
            //选部门  有可能选到其他公司的部门  所以如果不传部门  才加上税号的查询条件
            param.setXfsh(nsrsbh);
        }

        Page<XxFptjKehuDTO> page = new Page<>(param.getPageNo(), param.getPageSize());

        XxFptjKehuParam xxFptjKehuParam = new XxFptjKehuParam();
        BeanUtils.copyProperties(param, xxFptjKehuParam);
        IPage<XxFptjKehuDTO> list = fptjService.getXxFpxxtjKehu(page, xxFptjKehuParam);
        return Result.OK(list);
    }

    @ApiOperation(value = "发票统计-按客户-导出excel", notes = "发票统计-按客户-导出excel")
    @RequestMapping(value = "/fptjKehuExportXls", method = RequestMethod.POST)
    public void fptjKehuExportXls(HttpServletRequest request, HttpServletResponse response, @RequestBody XxFptjKehuParam param) {
        String nsrsbh = LoginUserUtil.getQyxxByLoginUser().getNsrsbh();
        if (StringUtils.isNotEmpty(param.getKpzddm())) {
            CommonParam commonParam = kpzdService.getCommonParamByKpzd(param.getKpzddm());
            nsrsbh = commonParam.getQyxx().getNsrsbh();
        }
        if (StringUtils.isNotBlank(param.getSysOrgCode())) {
            String[] orgcodes = param.getSysOrgCode().split(",");
            param.setSysOrgCodeArr(new ArrayList<>(Arrays.asList(orgcodes)));
        } else {
            //选部门  有可能选到其他公司的部门  所以如果不传部门  才加上税号的查询条件
            param.setXfsh(nsrsbh);
        }

        List<XxFptjKehuDTO> list = fptjService.getXxFpxxtjKehu(param);
        String title = "发票统计(按客户)";
        ExcelUtils.exportExcel(list, title, title, XxFptjKehuDTO.class, title, response);
    }

    @AutoLog(value = "发票统计-按税额")
    @ApiOperation(value = "发票统计-按税额", notes = "发票统计-按税额")
    @PostMapping(value = "/fptjSe")
    public Result<List<XxFptjSeDTO>> fptjSe(@RequestBody XxFptjSeParam param) {
        if (StringUtils.isEmpty(param.getSysOrgCode())) {
            String nsrsbh = LoginUserUtil.getQyxxByLoginUser().getNsrsbh();
            param.setXfsh(nsrsbh);
        } else {
            param.setSysOrgCodeArr(param.getSysOrgCode().split(","));
        }
        List<XxFptjSeDTO> list = fptjService.getXxFpxxtjSe(param);
        return Result.OK(list);
    }

    @ApiOperation(value = "发票统计-按税额-导出excel", notes = "发票统计-按税额-导出excel")
    @RequestMapping(value = "/fptjSeExportXls", method = RequestMethod.POST)
    public void fptjSeExportXls(HttpServletRequest request, HttpServletResponse response, @RequestBody XxFptjSeParam param) {
        String nsrsbh = LoginUserUtil.getQyxxByLoginUser().getNsrsbh();
        if (StringUtils.isNotBlank(param.getSysOrgCode())) {
            String[] orgcodes = param.getSysOrgCode().split(",");
            param.setSysOrgCodeArr(orgcodes);
        } else {
            //选部门  有可能选到其他公司的部门  所以如果不传部门  才加上税号的查询条件
            param.setXfsh(nsrsbh);
        }

        List<XxFptjSeDTO> list = fptjService.getXxFpxxtjSe(param);
        String title = "发票统计(按税额)";
        ExcelUtils.exportExcel(list, title, title, XxFptjSeDTO.class, title, response);
    }
}
